import { useRef, useState } from 'react';

import { useRequest } from 'ahooks';
import { Button, Card, Popconfirm, Tree, TreeProps } from 'antd';
import { DataNode } from 'antd/lib/tree';
import { cloneDeep } from 'lodash-es';

import Text from '@/components/text';

import { store } from '@/store';

import { usePermission } from '@/auth';
import {
  orgDeptInfoDelete,
  orgDeptInfoSortList,
  orgDeptInfoTreeList
} from '@/services/base/bumenguanlibumenxiangguanjiekou';

import Edit, { EditRef } from './edit';
import styles from './index.module.scss';

export type BizObject = BASE.OrgDeptInfoVo;

/**
 * 搜索树
 */
const loopTree = <T extends DataNode>(
  list: T[],
  key: T['key'],
  cb: (node: T, i: number, list: T[]) => void
): void => {
  for (let i = 0; i < list.length; i++) {
    if (list[i].key === key) {
      return cb(list[i], i, list);
    }

    if (Array.isArray(list[i].children)) {
      loopTree(list[i].children as T[], key, cb);
    }
  }
};

export type DeptDataNode = DataNode & {
  value: number;
  data: BASE.OrgDeptInfoVo;
  children?: DeptDataNode[];
};

export type DeptProps = TreeProps<DeptDataNode> & {
  onSelectDeptId?: (T: string | undefined) => void;
};

const Dept: React.FC<DeptProps> = ({ ...rest }) => {
  const permission = usePermission();
  const edit = useRef<EditRef>(null);
  const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
  const tree = useRequest(async () => {
    const res = await orgDeptInfoTreeList();

    const formatDeptData = (data: BASE.OrgDeptInfoVo[]): DeptDataNode[] => {
      const result: DeptDataNode[] = [];

      data.forEach((item) => {
        const node: DeptDataNode = {
          title: item.deptName,
          key: item.id!,
          value: item.id!,
          data: item,
          children: []
        };

        if (item.child && item.child.length > 0) {
          node.children = formatDeptData(item.child);
        }

        result.push(node);
      });

      return result;
    };

    return formatDeptData(res.data || []);
  });
  const updateSort = useRequest(
    async (
      query: ArgumentsType<typeof orgDeptInfoSortList>[0],
      rollbackTreeData: DeptDataNode[]
    ) => {
      try {
        const res = await orgDeptInfoSortList(query);

        store.app?.message.success('修改成功');

        return res.data;
      } catch (e) {
        // 回滚
        tree.mutate(rollbackTreeData);
        throw e;
      }
    },
    {
      manual: true
    }
  );

  // 拖拽排序
  const onDrop: TreeProps<DeptDataNode>['onDrop'] = (e) => {
    const dropKey = e.node.key;
    const dragKey = e.dragNode.key;
    const dropPos = e.node.pos.split('-');
    const dropPosition = e.dropPosition - Number(dropPos[dropPos.length - 1]);
    const treeData = tree.data!;

    const rollbackTreeData = cloneDeep(treeData);
    const cloneTreeData = cloneDeep(treeData);

    loopTree(cloneTreeData, dragKey, (_, index, list) => {
      list.splice(index, 1);
    });

    if (!e.dropToGap || (e.node.children?.length && dropPosition === 1)) {
      // 添加到节点下面
      loopTree(cloneTreeData, dropKey, (item) => {
        item.children!.unshift(e.dragNode);

        // 修改pid
        item.children![0].data.pid = item.key as number;
      });
    } else {
      let findList: DeptDataNode[] = [];
      let findItem: DeptDataNode;
      let findIndex = 0;

      loopTree(cloneTreeData, dropKey, (item, index, list) => {
        findList = list;
        findItem = item;
        findIndex = index;
      });

      if (dropPosition === -1) {
        findList.splice(findIndex, 0, e.dragNode);
        // 修改pid
        findList[findIndex].data.pid = findItem!.data.pid;
      } else {
        findList.splice(findIndex + 1, 0, e.dragNode);
        // 修改pid
        findList[findIndex + 1].data.pid = findItem!.data.pid;
      }
    }

    // 前端先按照排序修改顺序, 当接口失败时回滚
    tree.mutate(cloneTreeData);

    /**
     * 修改放置后的节点的所有兄弟节点排序, 按照下标赋值
     */
    loopTree(cloneTreeData, dragKey, (...args) => {
      const list = args[2];

      // 修改请求参数
      const query: ArgumentsType<typeof orgDeptInfoSortList>[0] = [];

      list.forEach((item, index) => {
        item.data.sort = (index + 1) as unknown as string;

        query.push({
          id: item.data.id!,
          pid: item.data.pid!,
          deptName: item.data.deptName!,
          sort: index + 1
        });
      });

      updateSort.run(query, rollbackTreeData);
    });
  };

  const titleRender: TreeProps<DeptDataNode>['titleRender'] = (node) => {
    return (
      <div className={styles['node']}>
        <div className={styles['node-name']}>{node.data.deptName}</div>
        <Text.Space className={styles['node-action']}>
          {permission.check() && (
            <Text
              onClick={() => {
                edit.current?.open({
                  type: 'edit',
                  rowData: node.data,
                  onSuccess: () => {
                    tree.run();
                  }
                });
              }}
            >
              修改
            </Text>
          )}

          {permission.check() && (
            <Popconfirm
              title={`确定删除该部门吗？`}
              onConfirm={async () => {
                const res = await orgDeptInfoDelete({
                  id: node.data.id as unknown as string
                });

                store.app?.message.success(res.message);
                tree.run();

                return res.success;
              }}
            >
              <Text type="danger">删除</Text>
            </Popconfirm>
          )}
        </Text.Space>
      </div>
    );
  };

  return (
    <>
      <Card
        size="small"
        title="部门"
        extra={
          permission.check() && (
            <Button
              onClick={() => {
                edit.current?.open({
                  type: 'add',
                  onSuccess: () => {
                    tree.run();
                  }
                });
              }}
              type="link"
              size="small"
            >
              新增部门
            </Button>
          )
        }
      >
        <Tree<DeptDataNode>
          className={styles['dept']}
          treeData={tree.data}
          onDrop={onDrop}
          expandedKeys={expandedKeys}
          onExpand={setExpandedKeys as TreeProps<DeptDataNode>['onExpand']}
          blockNode
          draggable
          selectable
          titleRender={titleRender}
          onSelect={(val, { node }) => {
            if (!val?.length) {
              rest?.onSelectDeptId?.(undefined);
              return;
            }
            rest?.onSelectDeptId?.(val?.[0] as unknown as string);
            console.log('v', val, node);
          }}
          {...rest}
        />
      </Card>

      <Edit ref={edit} treeData={tree.data || []} />
    </>
  );
};

export default Dept;
